1 /*
2 * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package sun.security.util;
27
28 import java.io.ByteArrayOutputStream;
29 import java.io.OutputStream;
30 import java.io.IOException;
31 import java.text.SimpleDateFormat;
32 import java.util.Date;
33 import java.util.TimeZone;
34 import java.util.Comparator;
35 import java.util.Arrays;
36 import java.math.BigInteger;
37 import java.util.Locale;
38
39
40 /**
41 * Output stream marshaling DER-encoded data. This is eventually provided
42 * in the form of a byte array; there is no advance limit on the size of
43 * that byte array.
44 *
45 * <P>At this time, this class supports only a subset of the types of
46 * DER data encodings which are defined. That subset is sufficient for
47 * generating most X.509 certificates.
48 *
49 *
50 * @author David Brownell
51 * @author Amit Kapoor
52 * @author Hemma Prafullchandra
53 */
54 public class DerOutputStream
55 extends ByteArrayOutputStream implements DerEncoder {
56 /**
57 * Construct an DER output stream.
58 *
59 * @param size how large a buffer to preallocate.
60 */
61 public DerOutputStream(int size) { super(size); }
62
63 /**
64 * Construct an DER output stream.
65 */
66 public DerOutputStream() { }
67
68 /**
69 * Writes tagged, pre-marshaled data. This calcuates and encodes
70 * the length, so that the output data is the standard triple of
71 * { tag, length, data } used by all DER values.
72 *
73 * @param tag the DER value tag for the data, such as
74 * <em>DerValue.tag_Sequence</em>
75 * @param buf buffered data, which must be DER-encoded
76 */
77 public void write(byte tag, byte[] buf) throws IOException {
78 write(tag);
79 putLength(buf.length);
80 write(buf, 0, buf.length);
81 }
82
83 /**
84 * Writes tagged data using buffer-to-buffer copy. As above,
85 * this writes a standard DER record. This is often used when
86 * efficiently encapsulating values in sequences.
87 *
88 * @param tag the DER value tag for the data, such as
89 * <em>DerValue.tag_Sequence</em>
90 * @param out buffered data
91 */
92 public void write(byte tag, DerOutputStream out) throws IOException {
93 write(tag);
94 putLength(out.count);
95 write(out.buf, 0, out.count);
96 }
97
98 /**
99 * Writes implicitly tagged data using buffer-to-buffer copy. As above,
100 * this writes a standard DER record. This is often used when
101 * efficiently encapsulating implicitly tagged values.
102 *
103 * @param tag the DER value of the context-specific tag that replaces
104 * original tag of the value in the output, such as in
105 * <pre>
106 * <em> <field> [N] IMPLICIT <type></em>
107 * </pre>
108 * For example, <em>FooLength [1] IMPLICIT INTEGER</em>, with value=4;
109 * would be encoded as "81 01 04" whereas in explicit
110 * tagging it would be encoded as "A1 03 02 01 04".
111 * Notice that the tag is A1 and not 81, this is because with
112 * explicit tagging the form is always constructed.
113 * @param value original value being implicitly tagged
114 */
115 public void writeImplicit(byte tag, DerOutputStream value)
116 throws IOException {
117 write(tag);
118 write(value.buf, 1, value.count-1);
119 }
120
121 /**
122 * Marshals pre-encoded DER value onto the output stream.
123 */
124 public void putDerValue(DerValue val) throws IOException {
125 val.encode(this);
126 }
127
128 /*
129 * PRIMITIVES -- these are "universal" ASN.1 simple types.
130 *
131 * BOOLEAN, INTEGER, BIT STRING, OCTET STRING, NULL
132 * OBJECT IDENTIFIER, SEQUENCE(OF), SET(OF)
133 * PrintableString, T61String, IA5String, UTCTime
134 */
135
136 /**
137 * Marshals a DER boolean on the output stream.
138 */
139 public void putBoolean(boolean val) throws IOException {
140 write(DerValue.tag_Boolean);
141 putLength(1);
142 if (val) {
143 write(0xff);
144 } else {
145 write(0);
146 }
147 }
148
149 /**
150 * Marshals a DER enumerated on the output stream.
151 * @param i the enumerated value.
152 */
153 public void putEnumerated(int i) throws IOException {
154 write(DerValue.tag_Enumerated);
155 putIntegerContents(i);
156 }
157
158 /**
159 * Marshals a DER integer on the output stream.
160 *
161 * @param i the integer in the form of a BigInteger.
162 */
163 public void putInteger(BigInteger i) throws IOException {
164 write(DerValue.tag_Integer);
165 byte[] buf = i.toByteArray(); // least number of bytes
166 putLength(buf.length);
167 write(buf, 0, buf.length);
168 }
169
170 /**
171 * Marshals a DER integer on the output stream.
172 * @param i the integer in the form of an Integer.
173 */
174 public void putInteger(Integer i) throws IOException {
175 putInteger(i.intValue());
176 }
177
178 /**
179 * Marshals a DER integer on the output stream.
180 * @param i the integer.
181 */
182 public void putInteger(int i) throws IOException {
183 write(DerValue.tag_Integer);
184 putIntegerContents(i);
185 }
186
187 private void putIntegerContents(int i) throws IOException {
188
189 byte[] bytes = new byte[4];
190 int start = 0;
191
192 // Obtain the four bytes of the int
193
194 bytes[3] = (byte) (i & 0xff);
195 bytes[2] = (byte)((i & 0xff00) >>> 8);
196 bytes[1] = (byte)((i & 0xff0000) >>> 16);
197 bytes[0] = (byte)((i & 0xff000000) >>> 24);
198
199 // Reduce them to the least number of bytes needed to
200 // represent this int
201
202 if (bytes[0] == (byte)0xff) {
203
204 // Eliminate redundant 0xff
205
206 for (int j = 0; j < 3; j++) {
207 if ((bytes[j] == (byte)0xff) &&
208 ((bytes[j+1] & 0x80) == 0x80))
209 start++;
210 else
211 break;
212 }
213 } else if (bytes[0] == 0x00) {
214
215 // Eliminate redundant 0x00
216
217 for (int j = 0; j < 3; j++) {
218 if ((bytes[j] == 0x00) &&
219 ((bytes[j+1] & 0x80) == 0))
220 start++;
221 else
222 break;
223 }
224 }
225
226 putLength(4 - start);
227 for (int k = start; k < 4; k++)
228 write(bytes[k]);
229 }
230
231 /**
232 * Marshals a DER bit string on the output stream. The bit
233 * string must be byte-aligned.
234 *
235 * @param bits the bit string, MSB first
236 */
237 public void putBitString(byte[] bits) throws IOException {
238 write(DerValue.tag_BitString);
239 putLength(bits.length + 1);
240 write(0); // all of last octet is used
241 write(bits);
242 }
243
244 /**
245 * Marshals a DER bit string on the output stream.
246 * The bit strings need not be byte-aligned.
247 *
248 * @param bits the bit string, MSB first
249 */
250 public void putUnalignedBitString(BitArray ba) throws IOException {
251 byte[] bits = ba.toByteArray();
252
253 write(DerValue.tag_BitString);
254 putLength(bits.length + 1);
255 write(bits.length*8 - ba.length()); // excess bits in last octet
256 write(bits);
257 }
258
259 /**
260 * Marshals a truncated DER bit string on the output stream.
261 * The bit strings need not be byte-aligned.
262 *
263 * @param bits the bit string, MSB first
264 */
265 public void putTruncatedUnalignedBitString(BitArray ba) throws IOException {
266 putUnalignedBitString(ba.truncate());
267 }
268
269 /**
270 * DER-encodes an ASN.1 OCTET STRING value on the output stream.
271 *
272 * @param octets the octet string
273 */
274 public void putOctetString(byte[] octets) throws IOException {
275 write(DerValue.tag_OctetString, octets);
276 }
277
278 /**
279 * Marshals a DER "null" value on the output stream. These are
280 * often used to indicate optional values which have been omitted.
281 */
282 public void putNull() throws IOException {
283 write(DerValue.tag_Null);
284 putLength(0);
285 }
286
287 /**
288 * Marshals an object identifier (OID) on the output stream.
289 * Corresponds to the ASN.1 "OBJECT IDENTIFIER" construct.
290 */
291 public void putOID(ObjectIdentifier oid) throws IOException {
292 oid.encode(this);
293 }
294
295 /**
296 * Marshals a sequence on the output stream. This supports both
297 * the ASN.1 "SEQUENCE" (zero to N values) and "SEQUENCE OF"
298 * (one to N values) constructs.
299 */
300 public void putSequence(DerValue[] seq) throws IOException {
301 DerOutputStream bytes = new DerOutputStream();
302 int i;
303
304 for (i = 0; i < seq.length; i++)
305 seq[i].encode(bytes);
306
307 write(DerValue.tag_Sequence, bytes);
308 }
309
310 /**
311 * Marshals the contents of a set on the output stream without
312 * ordering the elements. Ok for BER encoding, but not for DER
313 * encoding.
314 *
315 * For DER encoding, use orderedPutSet() or orderedPutSetOf().
316 */
317 public void putSet(DerValue[] set) throws IOException {
318 DerOutputStream bytes = new DerOutputStream();
319 int i;
320
321 for (i = 0; i < set.length; i++)
322 set[i].encode(bytes);
323
324 write(DerValue.tag_Set, bytes);
325 }
326
327 /**
328 * Marshals the contents of a set on the output stream. Sets
329 * are semantically unordered, but DER requires that encodings of
330 * set elements be sorted into ascending lexicographical order
331 * before being output. Hence sets with the same tags and
332 * elements have the same DER encoding.
333 *
334 * This method supports the ASN.1 "SET OF" construct, but not
335 * "SET", which uses a different order.
336 */
337 public void putOrderedSetOf(byte tag, DerEncoder[] set) throws IOException {
338 putOrderedSet(tag, set, lexOrder);
339 }
340
341 /**
342 * Marshals the contents of a set on the output stream. Sets
343 * are semantically unordered, but DER requires that encodings of
344 * set elements be sorted into ascending tag order
345 * before being output. Hence sets with the same tags and
346 * elements have the same DER encoding.
347 *
348 * This method supports the ASN.1 "SET" construct, but not
349 * "SET OF", which uses a different order.
350 */
351 public void putOrderedSet(byte tag, DerEncoder[] set) throws IOException {
352 putOrderedSet(tag, set, tagOrder);
353 }
354
355 /**
356 * Lexicographical order comparison on byte arrays, for ordering
357 * elements of a SET OF objects in DER encoding.
358 */
359 private static ByteArrayLexOrder lexOrder = new ByteArrayLexOrder();
360
361 /**
362 * Tag order comparison on byte arrays, for ordering elements of
363 * SET objects in DER encoding.
364 */
365 private static ByteArrayTagOrder tagOrder = new ByteArrayTagOrder();
366
367 /**
368 * Marshals a the contents of a set on the output stream with the
369 * encodings of its sorted in increasing order.
370 *
371 * @param order the order to use when sorting encodings of components.
372 */
373 private void putOrderedSet(byte tag, DerEncoder[] set,
374 Comparator<byte[]> order) throws IOException {
375 DerOutputStream[] streams = new DerOutputStream[set.length];
376
377 for (int i = 0; i < set.length; i++) {
378 streams[i] = new DerOutputStream();
379 set[i].derEncode(streams[i]);
380 }
381
382 // order the element encodings
383 byte[][] bufs = new byte[streams.length][];
384 for (int i = 0; i < streams.length; i++) {
385 bufs[i] = streams[i].toByteArray();
386 }
387 Arrays.<byte[]>sort(bufs, order);
388
389 DerOutputStream bytes = new DerOutputStream();
390 for (int i = 0; i < streams.length; i++) {
391 bytes.write(bufs[i]);
392 }
393 write(tag, bytes);
394
395 }
396
397 /**
398 * Marshals a string as a DER encoded UTF8String.
399 */
400 public void putUTF8String(String s) throws IOException {
401 writeString(s, DerValue.tag_UTF8String, "UTF8");
402 }
403
404 /**
405 * Marshals a string as a DER encoded PrintableString.
406 */
407 public void putPrintableString(String s) throws IOException {
408 writeString(s, DerValue.tag_PrintableString, "ASCII");
409 }
410
411 /**
412 * Marshals a string as a DER encoded T61String.
413 */
414 public void putT61String(String s) throws IOException {
415 /*
416 * Works for characters that are defined in both ASCII and
417 * T61.
418 */
419 writeString(s, DerValue.tag_T61String, "ISO-8859-1");
420 }
421
422 /**
423 * Marshals a string as a DER encoded IA5String.
424 */
425 public void putIA5String(String s) throws IOException {
426 writeString(s, DerValue.tag_IA5String, "ASCII");
427 }
428
429 /**
430 * Marshals a string as a DER encoded BMPString.
431 */
432 public void putBMPString(String s) throws IOException {
433 writeString(s, DerValue.tag_BMPString, "UnicodeBigUnmarked");
434 }
435
436 /**
437 * Marshals a string as a DER encoded GeneralString.
438 */
439 public void putGeneralString(String s) throws IOException {
440 writeString(s, DerValue.tag_GeneralString, "ASCII");
441 }
442
443 /**
444 * Private helper routine for writing DER encoded string values.
445 * @param s the string to write
446 * @param stringTag one of the DER string tags that indicate which
447 * encoding should be used to write the string out.
448 * @param enc the name of the encoder that should be used corresponding
449 * to the above tag.
450 */
451 private void writeString(String s, byte stringTag, String enc)
452 throws IOException {
453
454 byte[] data = s.getBytes(enc);
455 write(stringTag);
456 putLength(data.length);
457 write(data);
458 }
459
460 /**
461 * Marshals a DER UTC time/date value.
462 *
463 * <P>YYMMDDhhmmss{Z|+hhmm|-hhmm} ... emits only using Zulu time
464 * and with seconds (even if seconds=0) as per RFC 3280.
465 */
466 public void putUTCTime(Date d) throws IOException {
467 putTime(d, DerValue.tag_UtcTime);
468 }
469
470 /**
471 * Marshals a DER Generalized Time/date value.
472 *
473 * <P>YYYYMMDDhhmmss{Z|+hhmm|-hhmm} ... emits only using Zulu time
474 * and with seconds (even if seconds=0) as per RFC 3280.
475 */
476 public void putGeneralizedTime(Date d) throws IOException {
477 putTime(d, DerValue.tag_GeneralizedTime);
478 }
479
480 /**
481 * Private helper routine for marshalling a DER UTC/Generalized
482 * time/date value. If the tag specified is not that for UTC Time
483 * then it defaults to Generalized Time.
484 * @param d the date to be marshalled
485 * @param tag the tag for UTC Time or Generalized Time
486 */
487 private void putTime(Date d, byte tag) throws IOException {
488
489 /*
490 * Format the date.
491 */
492
493 TimeZone tz = TimeZone.getTimeZone("GMT");
494 String pattern = null;
495
496 if (tag == DerValue.tag_UtcTime) {
497 pattern = "yyMMddHHmmss'Z'";
498 } else {
499 tag = DerValue.tag_GeneralizedTime;
500 pattern = "yyyyMMddHHmmss'Z'";
501 }
502
503 SimpleDateFormat sdf = new SimpleDateFormat(pattern, Locale.US);
504 sdf.setTimeZone(tz);
505 byte[] time = (sdf.format(d)).getBytes("ISO-8859-1");
506
507 /*
508 * Write the formatted date.
509 */
510
511 write(tag);
512 putLength(time.length);
513 write(time);
514 }
515
516 /**
517 * Put the encoding of the length in the stream.
518 *
519 * @params len the length of the attribute.
520 * @exception IOException on writing errors.
521 */
522 public void putLength(int len) throws IOException {
523 if (len < 128) {
524 write((byte)len);
525
526 } else if (len < (1 << 8)) {
527 write((byte)0x081);
528 write((byte)len);
529
530 } else if (len < (1 << 16)) {
531 write((byte)0x082);
532 write((byte)(len >> 8));
533 write((byte)len);
534
535 } else if (len < (1 << 24)) {
536 write((byte)0x083);
537 write((byte)(len >> 16));
538 write((byte)(len >> 8));
539 write((byte)len);
540
541 } else {
542 write((byte)0x084);
543 write((byte)(len >> 24));
544 write((byte)(len >> 16));
545 write((byte)(len >> 8));
546 write((byte)len);
547 }
548 }
549
550 /**
551 * Put the tag of the attribute in the stream.
552 *
553 * @params class the tag class type, one of UNIVERSAL, CONTEXT,
554 * APPLICATION or PRIVATE
555 * @params form if true, the value is constructed, otherwise it is
556 * primitive.
557 * @params val the tag value
558 */
559 public void putTag(byte tagClass, boolean form, byte val) {
560 byte tag = (byte)(tagClass | val);
561 if (form) {
562 tag |= (byte)0x20;
563 }
564 write(tag);
565 }
566
567 /**
568 * Write the current contents of this <code>DerOutputStream</code>
569 * to an <code>OutputStream</code>.
570 *
571 * @exception IOException on output error.
572 */
573 public void derEncode(OutputStream out) throws IOException {
574 out.write(toByteArray());
575 }
576 }